#pragma once
#include <cstdint>
#include <unordered_map>
#include <utility>
#include "ConfigInfo.h"
namespace xncc {
namespace config {
    /*
      IPC线程PUB消息的Queue信息
    */
    struct ValidIPCRingQueueInfo
    {
        int32_t Id;
        int32_t Size;
        int32_t SubTid;
        bool    AutoExpand;
        using s_ptr = std::shared_ptr<ValidIPCRingQueueInfo>;
    };
    /*
      业务线程之间转发消息的Queue信息
    */
    struct ValidBusiRingQueueInfo
    {
        int32_t              Id;
        int32_t              Size;
        int32_t              SubTid;
        std::vector<int32_t> MsgCodes;
        bool                 AutoExpand;
        using s_ptr = std::shared_ptr<ValidBusiRingQueueInfo>;
    };
    class ConfMgr
    {
      public:
        ConfMgr();
        ~ConfMgr() = default;

        ConfMgr(const ConfMgr&)             = delete;
        ConfMgr(const ConfMgr&&)            = delete;
        ConfMgr& operator=(const ConfMgr&)  = delete;
        ConfMgr& operator=(const ConfMgr&&) = delete;

        auto init() -> std::pair<int, std::string>;
        auto loadCfgFile(const std::string&) -> int;
        auto loadCfgString(const std::string&) -> int;
        auto Cfg() -> const PlatformInfo& { return platformInfo_; }

        auto getIPCPubQueues() const -> const std::unordered_map<int32_t, std::vector<ValidIPCRingQueueInfo::s_ptr>>&
        {
            return ipcPubRingQueues;
        }
        auto getBusiPubQueues() const -> const std::unordered_map<int32_t, std::vector<ValidBusiRingQueueInfo::s_ptr>>&
        {
            return busiPubRingQueues;
        }

      private:
        std::pair<int, std::string> checkConf();
        std::pair<int, std::string> checkRingQueue();
        std::pair<int, std::string> checkAllBusiThread();
        std::pair<int, std::string> checkAllIPCThread();
        std::pair<int, std::string> checkThreadId();
        std::pair<int, std::string> checkQueueRace();

        void genRealRingQueues();
        void classifyRingQueues();

        std::pair<int, std::string> checkBusiThread(const BusiThreadInfo& busi);
        std::pair<int, std::string> checkServerThread(const ServerThreadInfo& ioThread);
        std::pair<int, std::string> checkSubServerThread(const SubServerThreadInfo& ioThread);
        std::pair<int, std::string> checkClientThread(const ClientThreadInfo& ioThread);

        template <typename T>
        bool        hasRepeated(const std::vector<T>& srcList);
        bool        hasUndefineId(const std::vector<int32_t>& idList);
        static bool hasSelfSubPub(const std::vector<int32_t>& subIds, const std::vector<int32_t>& pubIds);

        struct RealRingQueueInfo  // 不提供对外访问
        {
            RingQueueInfo        CfgQueueInfo;    // 队列的属性信息
            std::vector<int32_t> SubTids;         // 订阅这个Queue的线程ID，因为可能存在多个订阅者
            std::vector<int32_t> PubTids;         // 往这个Queue发数据的线程ID，只能有一个
            std::vector<int32_t> MsgCodes;        // 这个ID会接收哪些消息
            bool                 IsIpcThreadPub;  // 是否是IPC线程发布数据的队列
            using s_ptr = std::shared_ptr<RealRingQueueInfo>;
        };
        const std::string                          FILE_PATH_;
        PlatformInfo                               platformInfo_;
        std::unordered_map<int32_t, RingQueueInfo> originRingQueues;

        /**
         * key是配置文件中的队列ID value是涉及到这个ID的所有信息
         */
        std::unordered_map<int32_t, RealRingQueueInfo::s_ptr> realRingQueues;

        /**
         * key是配置文件中的IPC线程的ID value是IPC线程发布数据队列信息 为什么有多个 虽然配置只配了一个ID
         * 但是多个订阅者的情况下 就会产生多个队列 subTid  pubTid Id 三者构成唯一的队列
         */
        std::unordered_map<int32_t, std::vector<ValidIPCRingQueueInfo::s_ptr>> ipcPubRingQueues;

        /**
         * key是配置文件中的业务线程的ID value是业务线程发布数据队列信息 业务线程可以发布数据到多个队列
         */
        std::unordered_map<int32_t, std::vector<ValidBusiRingQueueInfo::s_ptr>> busiPubRingQueues;
    };
}  // namespace config
}  // namespace xncc
